package com.xhkj.shirodemo.utils;


import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 用来操作数据库: 增删查改
 * @author:Teacher黄
 * @date:Created at 2019/12/10
 */
@SuppressWarnings("all")
public class DbUtil {

    /**
     * 连接数据库的对象
     */
    private static Connection connection;
    private static String driver;
    private static String url="jdbc:mysql://localhost:3306/mydb";
    private static String userName="root";
    private static String password="123456";

    static {

        try {
            // 加载配置
//            load("db.properties");
            // 链接数据库
            connect();
        } catch (IOException e) {
            System.out.println("配置文件加载失败");
        } catch (Exception e) {
            System.out.println("连接数据库失败");
        }

    }


    /**
     * 加载配置文件
     * @param location : 配置文件的位置
     */
    private static void load(String location) throws IOException {
        // 加载配置文件
        InputStream inputStream = DbUtil.class.getClassLoader().getResourceAsStream(location);
        //
        Properties properties = new Properties();
        properties.load(inputStream);
        // 获取对应的配置
        driver = properties.getProperty("driver");
        url = properties.getProperty("url");
        userName = properties.getProperty("userName");
        password = properties.getProperty("password");
    }

    /**
     * 连接数据库
     */
    private static void connect() throws Exception {
        // 加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 获取连接
        connection = DriverManager.getConnection(url, userName, password);
    }


    /**
     * 查询所有,无条件
     * @param sql
     * @param tClass
     * @param <T>
     * @return 返回一个集合
     */
    public static <T> List<T> select(String sql, Class<T> tClass) {
        // 存放查询的数据
        List<T> dataList = new ArrayList<>();
        try {
                PreparedStatement preparedStatement = connection.prepareStatement(sql);
                // 执行 得到 结果集对象
                ResultSet resultSet = preparedStatement.executeQuery();
                // 通过结果集去获取 元数据 => 获取列的个数以及列名
                ResultSetMetaData metaData = resultSet.getMetaData();
                // 获取总共的列的个数
                int columnCount = metaData.getColumnCount();
                // 通过遍历去获取结果集中的值
                while (resultSet.next()) {
                    // 每循环一次是一个新的对象
                    Object obj = tClass.getConstructor().newInstance();
                    // 遍历列的个数=> 为了依次去获取列名
                    for (int i = 1; i <= columnCount; i++) {
                        // 列名就是属性名字
                        String columnName = metaData.getColumnName(i);
                        // 获取属性对象
                        Field field = tClass.getDeclaredField(columnName);
                        // 组装对应的setter方法
                        String fieldSetterMethodName = "set" + firstToUpperCase(columnName);
                        // 获取对应的方法对象
                        Method method = tClass.getDeclaredMethod(fieldSetterMethodName, field.getType());
                        // 动态的invoke
                        // 数据的转换
                        String columnValue = resultSet.getString(columnName);
                        Object fieldValue = null;
                        if (field.getType().getName().equals("Timestamp")){
                            fieldValue = Timestamp.valueOf(columnValue);
                        }else {
                            fieldValue = field.getType().getConstructor(String.class).newInstance(columnValue);
                        }
                        method.invoke(obj, fieldValue);
                    }
                    // 将查询的结果放入dataList
                    dataList.add((T)obj);
                }

            } catch(SQLException e){
                System.out.println("sql有问题!");
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }

        return dataList;
    }


    /**
     * 查询所有, 可以传递条件参数
     * @param sql : 需要执行的sql
     * @param tClass : 对应类型的CLass对象
     * @param params : 条件的实参
     * @param <T>
     * @return 返回一个集合
     */
    public static <T> List<T> select(String sql, Class<T> tClass,Object... params) {
        // 存放查询的数据
        List<T> dataList = new ArrayList<>();
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);

            // 填坑
            for (int i = 0; i < params.length; i++) {
                preparedStatement.setObject(i+1,params[i]);
            }

            // 执行 得到 结果集对象
            ResultSet resultSet = preparedStatement.executeQuery();
            // 通过结果集去获取 元数据 => 获取列的个数以及列名
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 获取总共的列的个数
            int columnCount = metaData.getColumnCount();
            // 通过遍历去获取结果集中的值
            while (resultSet.next()) {
                // 每循环一次是一个新的对象
                Object obj = tClass.getConstructor().newInstance();
                // 遍历列的个数=> 为了依次去获取列名
                for (int i = 1; i <= columnCount; i++) {
                    // 列名就是属性名字
                    String columnName = metaData.getColumnName(i);
                    // 获取属性对象
                    Field field = tClass.getDeclaredField(columnName);
                    // 组装对应的setter方法
                    String fieldSetterMethodName = "set" + firstToUpperCase(columnName);
                    // 获取对应的方法对象
                    Method method = tClass.getDeclaredMethod(fieldSetterMethodName, field.getType());
                    // 动态的invoke
                    // 数据的转换
                    String columnValue = resultSet.getString(columnName);
                    Object fieldValue = null;
                    if (field.getType().getName().equals("Timestamp")){
                        fieldValue = Timestamp.valueOf(columnValue);
                    }else {
                        fieldValue = field.getType().getConstructor(String.class).newInstance(columnValue);
                    }
                    method.invoke(obj, fieldValue);
                }
                // 将查询的结果放入dataList
                dataList.add((T)obj);
            }

        } catch(SQLException e){
            System.out.println("sql有问题!");
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        return dataList;
    }

    /**
     * 查询单条数据
     * @param sql
     * @param tClass
     * @param params
     * @param <T>
     * @return 返回一个对象
     */
    public static <T> T findOne(String sql, Class<T> tClass,Object... params) {
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 填坑
            for (int i = 0; i < params.length; i++) {
                preparedStatement.setObject(i+1,params[i]);
            }
            // 执行 得到 结果集对象
            ResultSet resultSet = preparedStatement.executeQuery();
            // 通过结果集去获取 元数据 => 获取列的个数以及列名
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 获取总共的列的个数
            int columnCount = metaData.getColumnCount();
            // 通过遍历去获取结果集中的值
            while (resultSet.next()) {
                // 每循环一次是一个新的对象
                Object obj = tClass.getConstructor().newInstance();
                // 遍历列的个数=> 为了依次去获取列名
                for (int i = 1; i <= columnCount; i++) {
                    // 列名就是属性名字
                    String columnName = metaData.getColumnName(i);
                    // 获取属性对象
                    Field field = tClass.getDeclaredField(columnName);
                    // 组装对应的setter方法
                    String fieldSetterMethodName = "set" + firstToUpperCase(columnName);
                    // 获取对应的方法对象
                    Method method = tClass.getDeclaredMethod(fieldSetterMethodName, field.getType());
                    // 动态的invoke
                    // 数据的转换
                    String columnValue = resultSet.getString(columnName);

                    Object fieldValue = null;
                    if (field.getType().getName().equals("Timestamp")){
                        fieldValue = Timestamp.valueOf(columnValue);
                    }else {
                        fieldValue = field.getType().getConstructor(String.class).newInstance(columnValue);
                    }
                    method.invoke(obj, fieldValue);
                }
                return (T)obj;
            }

        } catch(SQLException e){
            System.out.println("sql有问题!");
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 插入方法
     * @param sql
     * @param tClass
     * @param params
     * @param <T>
     * @return
     */
    public static Integer insert(String sql, Object... params) {
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 填坑
            for (int i = 0; i < params.length; i++) {
                preparedStatement.setObject(i+1,params[i]);
            }
            //执行sql语句
            return  preparedStatement.executeUpdate();
        } catch(SQLException e){
            System.out.println("sql有问题!");
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 首字母大写
     * @param name
     * @return
     */
    public static String firstToUpperCase(String name){
        if (name == null || name.isEmpty()) {
            return null;
        }
        return name.substring(0,1).toUpperCase()+name.substring(1);
    }
}
